/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2008 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_ENCODER)

#include <trace_log.h>
#include "umc_avs_enc_compressor.h"
#include "umc_avs_picture_header.h"
#include "umc_avs_slice.h"
#include "umc_avs_pic.h"
#include "umc_avs_sequence_header.h"
#include "umc_avs_enc_tables.h"
#include "umc_avs_enc_vlc.h"

#include "umc_avs_enc_bit_stream.h"

namespace UMC
{

void AVSCompressor::CompressPMacroBlocksRow(void)
{
    Ipp32u MbTypeIndex;

    MbMax = m_encCtx.MbIndex + m_encCtx.MbWidth;

    // we can use MbIndex either from decoding and reconstructing contexts
    MbIndex = m_encCtx.MbIndex;

    PrepareNeighbours(&m_encCtx);
    PrepareDisassembling();
    PrepareDecoding();
    PrepareReconstruction();
    CompressSliceHeader();

    do
    {
        if (0 == MbIndex)
        {
            WRITE_TRACE_LOG(_enc_tst, "Frame num is  ", m_encCtx.m_pPicHeader->picture_distance - 1);
            WRITE_TRACE_LOG(_vec_tst, "Frame num is  ", m_encCtx.m_pPicHeader->picture_distance - 1);
            WRITE_TRACE_LOG(_vec_final_tst, "Frame num is  ", m_encCtx.m_pPicHeader->picture_distance - 1);
            WRITE_TRACE_LOG(_rec_tst_enc, "Frame num is  ", m_encCtx.m_pPicHeader->picture_distance - 1);
        }
        WRITE_TRACE_LOG_MB_TITLE(_dis_tst, MbIndex, m_disCtx.MbWidth, m_disCtx.MbHeight, 0 == m_disCtx.m_pPicHeader->progressive_frame);
        WRITE_TRACE_LOG_MB_TITLE(_enc_tst, MbIndex, m_encCtx.MbWidth, m_encCtx.MbHeight, 0 == m_encCtx.m_pPicHeader->progressive_frame);
        WRITE_TRACE_LOG_MB_TITLE(_rec_tst_enc, MbIndex, m_recCtx.MbWidth, m_recCtx.MbHeight, 0 == m_recCtx.m_pPicHeader->progressive_frame);
        WRITE_TRACE_LOG_MB_TITLE(_rec, MbIndex, m_recCtx.MbWidth, m_recCtx.MbHeight, 0 == m_recCtx.m_pPicHeader->progressive_frame);
        WRITE_TRACE_LOG_MB_TITLE(_vec_tst, MbIndex, m_recCtx.MbWidth, m_recCtx.MbHeight, 0 == m_recCtx.m_pPicHeader->progressive_frame);
        WRITE_TRACE_LOG_MB_TITLE(_vec_final_tst, MbIndex, m_recCtx.MbWidth, m_recCtx.MbHeight, 0 == m_decCtx.m_pPicHeader->progressive_frame);


        // set the macro block info into the initial state
        // reset was done in EstimatePMacroBlocksRow
        //ResetMacroblock();

        // reset coefficient pointers
        m_pWriteCoeffs = (Ipp16s *)m_disCtx.m_pCoeffs;
        m_pReadCoeffs = m_encCtx.m_pCoeffs;

        // disassemble MB into parts
        //DisassemblePMacroBlock();
        
        // set Mb type
        //EncodePMacroBlockType();
        
        // check type of Mb and put into bitstream
        switch (m_pMbInfo->MbType)
        {
            case P_Skip:
                // nothing to disassemble, but
                // we should fill up statistic
                FillUpMeMbStatPMacroBlock();
                // encode MB into a bit stream
                EncodeSkipPMacroBlock();
                // reconstract P macroblock
                m_pReadCoeffs = m_encCtx.m_pCoeffs;
                ReconstructPMacroBlock();
                break;

            case I_8x8:
                // encode I Macro block type in P slice
                DisassembleIMacroBlock();
                // put mb type into bitstream
                MbTypeIndex = CBPOfMacroblock2Code[AVS_INTRA][m_pMbInfo->MbCBP] + 5;
                //MbTypeIndex = (m_pMbInfo->MbType) + 5;
                PutUE(&(m_encCtx.m_stream),MbTypeIndex);
                WRITE_TRACE_LOG(_enc_tst, "mb type", MbTypeIndex);
                // correct CBP
                //m_pMbInfo->MbCBP = CBPOfMacroblock2Code[AVS_INTRA][m_pMbInfo->MbCBP];
                // encode MB into a bit stream
                EncodeIMacroBlock();
                // reconstract macroblock
                m_pReadCoeffs = m_encCtx.m_pCoeffs;
                // rec was done in the Disassemble stage
                //ReconstructIMacroBlock();
                break;

            default:
                // disassemble MB into parts
                DisassemblePMacroBlock();
                // encode MB into a bit stream
                EncodePMacroBlock();
                // reconstract P macroblock
                m_pReadCoeffs = m_encCtx.m_pCoeffs;
                ReconstructPMacroBlock();
                break;
        };

        MbIndex += 1;
        AdvanceNeighbours();
        AdvanceDisassembling();
        AdvanceEncoding();
        AdvanceReconstruction();

    } while (MbIndex < MbMax);

    // update context
    FinalizeDisassembling();
    FinalizeEncoding();
    FinalizeReconstruction();

} // void AVSCompressor::CompressPMacroBlocksRow(void)

void AVSCompressor::EncodeSkipPMacroBlock(void)
{
    // set QP
    m_pMbInfo->QP = m_encCtx.PreviousQP;

    //Encode MB type
    if ( 0 == m_decCtx.m_pPicHeader->skip_mode_flag)
    {
        PutUE(&m_encCtx.m_stream, (m_pMbInfo->MbType) - 1 );
        WRITE_TRACE_LOG(_enc_tst, "mb type", (m_pMbInfo->MbType) -1);
        //Construct Motion Vectors for P Block
        //GetDiffMotionVectorsPSlice();
    }
    else
        m_encCtx.SkipMbCount++;
    
    //If row consist only from skipped Mbs
    if ( m_encCtx.SkipMbCount == m_encCtx.MbWidth )
    {
        PutUE(&m_encCtx.m_stream, m_decCtx.SkipMbCount + 1);
        WRITE_TRACE_LOG(_enc_tst, "skip mb count", m_decCtx.SkipMbCount + 1);
        m_encCtx.SkipMbCount = -1;
    }
    //if (-1 == m_decCtx.SkipMbCount)
    //{
    //    if (1 == m_encCtx.m_pPicHeader->skip_mode_flag)
    //    {
    //        PutUE(&m_decCtx.m_stream, -1);
    //        WRITE_TRACE_LOG(_dec_tst, "skip mb count", -1);
    //    }
    //}
    //else
    
    if ((NULL == m_pMbInfoTop) ||
        ((0 == m_pMbInfoTop->refIdx[AVS_FORWARD][2]) &&
         (m_pMbInfoTop->predType[2] & PredForward) &&
         (0 == m_pMbInfoTop->mv[AVS_FORWARD][2].scalar)))
    {
        m_mvPred.scalar = 0;
    }
    else if ((NULL == m_pMbInfoLeft) ||
             ((0 == m_pMbInfoLeft->refIdx[AVS_FORWARD][1]) &&
              (m_pMbInfoLeft->predType[1] & PredForward) &&
              (0 == m_pMbInfoLeft->mv[AVS_FORWARD][1].scalar)))
    {
        m_mvPred.scalar = 0;
    }
    else
    {
        GetMotionVectorPredictor16x16(PredForward, 0);
    }
    m_pMbInfo->mv[AVS_FORWARD][0] = m_mvPred;
    m_pMbInfo->mv[AVS_FORWARD][1] = m_mvPred;
    m_pMbInfo->mv[AVS_FORWARD][2] = m_mvPred;
    m_pMbInfo->mv[AVS_FORWARD][3] = m_mvPred;

    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][0].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][0].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][1].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][1].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][2].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][2].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);

    
} // void EncodeSkipPMacroBlock(void)

//void AVSCompressor::EncodePMacroBlockType(void)
//{
//    // 1 == skip_mode_flag; 
//    // indicates that the macroblock skip mode uses run-length coding
//    if (m_encCtx.m_pPicHeader->skip_mode_flag)
//    {
//        if (P_Skip == m_pMbInfo->MbType)
//        {                                                                                                                                                                                       
//            m_encCtx.SkipMbCount++;
//        }
//        else if (-1 == m_encCtx.SkipMbCount)
//        {
//            PutUE(&m_encCtx.m_stream, m_encCtx.SkipMbCount);
//            WRITE_TRACE_LOG(_enc_tst, "skip mb count", m_encCtx.SkipMbCount);
//        }
//        else
//        {
//            PutUE(&m_encCtx.m_stream, m_encCtx.SkipMbCount);
//            WRITE_TRACE_LOG(_enc_tst, "skip mb count", m_encCtx.SkipMbCount);
//        }
//    }
//
//} // void AVSCompressor::EncodePMacroBlockType(void)

void AVSCompressor::EncodePMacroBlock(void)
{
    Ipp32s i;
    
    // encode slice header
    if ((0 == m_encCtx.m_pPicHeader->picture_reference_flag) &&
        (I_PICTURE_START_CODE != m_encCtx.m_pPicHeader->picture_start_code))
    {
        //clone reference indices
        GetRefIndiciesPSlice();

        // frame structure - indecies are 1 bit wide
        if (m_encCtx.m_pPicHeader->picture_structure)
        {
            for (i = 0; i < m_pMbInfo->MvNum; i += 1)
            {
                PutBit(&m_encCtx.m_stream,m_refIdx[i]);
                WRITE_TRACE_LOG(_enc_tst, "mb reference index", m_refIdx[i]);
            }
        }
        // field structure - indecies are 2 bit wide
        else
        {
            for (i = 0; i < m_pMbInfo->MvNum; i += 1)
            {
                PutBits(&m_encCtx.m_stream,m_refIdx[i], 2);
                WRITE_TRACE_LOG(_enc_tst, "mb reference index", m_refIdx[i]);
            }
        }
    }
    
    //Encode MB type
    if (m_decCtx.m_pPicHeader->skip_mode_flag)
    {
        if (-1 == m_decCtx.SkipMbCount)
        {
            // put zero into bit stream (-1+1 = 0)
            PutUE(&m_encCtx.m_stream, m_encCtx.SkipMbCount + 1);
            WRITE_TRACE_LOG(_enc_tst, "skip mb count", m_encCtx.SkipMbCount + 1);
        }
        //all pervious Mb were skipped
        if ( 0 <= m_encCtx.SkipMbCount)
        {
            PutUE(&m_encCtx.m_stream, m_encCtx.SkipMbCount + 1);
            WRITE_TRACE_LOG(_enc_tst, "skip mb count", m_encCtx.SkipMbCount + 1);
            m_encCtx.SkipMbCount = -1;
        }
        PutUE(&m_encCtx.m_stream, m_pMbInfo->MbType - 2 );
        WRITE_TRACE_LOG(_enc_tst, "mb type", m_pMbInfo->MbType - 2);
        //Construct Motion Vectors for P Block
        GetRefIndiciesPSlice();
        GetDiffMotionVectorsPSlice();
    }
    else
    {
        PutUE(&m_encCtx.m_stream, (m_pMbInfo->MbType) - 1 );
        WRITE_TRACE_LOG(_enc_tst, "mb type", (m_pMbInfo->MbType) - 1);
        //Construct Motion Vectors for P Block
        GetRefIndiciesPSlice();
        GetDiffMotionVectorsPSlice();
    }

    // encode motion vectors
    for (i = 0; i < m_pMbInfo->MvNum; i += 1)
    {
        PutSE(&m_encCtx.m_stream, mv_diff[i].vector.x);
        WRITE_TRACE_LOG(_enc_tst, "mv diff x", mv_diff[i].vector.x);
        PutSE(&m_encCtx.m_stream, mv_diff[i].vector.y);
        WRITE_TRACE_LOG(_enc_tst, "mv diff y", mv_diff[i].vector.y);
    }
    
    // encode weighting prediction flag
    if (m_encCtx.m_pSlcHeader->mb_weighting_flag)
    {
        PutBit(&m_encCtx.m_stream, m_pMbInfo->weighting_prediction);
        WRITE_TRACE_LOG(_enc_tst, "weighting prediction", m_pMbInfo->weighting_prediction);
    }
    //else //no to encode
    //{
    //    if mb_weighting flag is zero,
    //    macroblock weighting prediction flag is equal to slice_weighting_flag
    //    m_pMbInfo->weighting_prediction = (Ipp8u) m_decCtx.m_pSlcHeader->slice_weighting_flag;
    //}
    //

    //For all types of pictures
    {
        Ipp32u uTemp;
        Ipp32s mb_qp_delta = 0;

        // encode coded block pattern
        uTemp = CBPOfMacroblock2Code[AVS_INTER][m_pMbInfo->MbCBP  & 0x3f];
        PutUE(&m_encCtx.m_stream, uTemp & 0x3f );
        WRITE_TRACE_LOG(_enc_tst, "CBP code", uTemp);
        
        // save additional chroma bits
        if (AVS_CHROMA_422_FORMAT == m_encCtx.m_pSeqHeader->chroma_format)
        {
            WRITE_TRACE_LOG(_enc_tst, "CBP code +", uTemp); 
            PutUE(&m_encCtx.m_stream, ((uTemp >> 6) & 0x3) );
        }

        // encode quantization parameter
        if ((m_pMbInfo->MbCBP) &&
            (0 == m_decCtx.FixedQP))
        {
            mb_qp_delta = m_pMbInfo->QP - m_encCtx.PreviousQP;
            PutSE(&m_encCtx.m_stream, mb_qp_delta);
            WRITE_TRACE_LOG(_enc_tst, "mb qp", m_pMbInfo->QP);
            WRITE_TRACE_LOG(_enc_tst, "mb qp delta", mb_qp_delta);
            m_encCtx.PreviousQP = m_pMbInfo->QP;
        }
        //    
        {
        Ipp32u i;
        Ipp32u uBlockMask = 1;

        // encode luminance blocks
        for (i = 0; i < 4; i += 1, uBlockMask += uBlockMask)
        {
            if (m_pMbInfo->MbCBP & uBlockMask)
            {
                avs_EncodeLumaBlockInter_AVS_1u16s(&m_encCtx.m_stream.dst,
                                                   &m_encCtx.m_stream.offset,
                                                   m_pReadCoeffs,
                                                   m_encCtx.ScanType);
                m_pReadCoeffs += 64;
            }
        }

        // encode chrominance blocks
        for (; i < m_encCtx.iNumberOfBlocks; i += 1, uBlockMask += uBlockMask)
        {
            if (m_pMbInfo->MbCBP & uBlockMask)
            {
                avs_EncodeChromaBlock_AVS_1u16s(&m_encCtx.m_stream.dst,
                                                &m_encCtx.m_stream.offset,
                                                m_pReadCoeffs,
                                                m_encCtx.ScanType);
                m_pReadCoeffs += 64;
            }
        }
        }

    }
} // void AVSCompressor::EncodePMacroBlock(void)

Ipp32u AVSCompressor::GetSizePMacroBlock(void)
{
    Ipp32u requiredSize = 0;
    Ipp32s i;
    
    // encode slice header
    if ((0 == m_encCtx.m_pPicHeader->picture_reference_flag) &&
        (I_PICTURE_START_CODE != m_encCtx.m_pPicHeader->picture_start_code))
    {
        //clone reference indices
        GetRefIndiciesPSlice();

        // frame structure - indecies are 1 bit wide
        if (m_encCtx.m_pPicHeader->picture_structure)
        {
            for (i = 0; i < m_pMbInfo->MvNum; i += 1)
            {
                //PutBit(&m_encCtx.m_stream,m_refIdx[i]);
                //WRITE_TRACE_LOG(_enc_tst, "mb reference index", m_refIdx[i]);
                requiredSize += 1;
            }
        }
        // field structure - indecies are 2 bit wide
        else
        {
            for (i = 0; i < m_pMbInfo->MvNum; i += 1)
            {
                //PutBits(&m_encCtx.m_stream,m_refIdx[i], 2);
                //WRITE_TRACE_LOG(_enc_tst, "mb reference index", m_refIdx[i]);
                requiredSize += 2;
            }
        }
    }
    
    //Encode MB type
    if (m_decCtx.m_pPicHeader->skip_mode_flag)
    {
        if (-1 == m_decCtx.SkipMbCount)
        {
            // put zero into bit stream (-1+1 = 0)
            //PutUE(&m_encCtx.m_stream, m_encCtx.SkipMbCount + 1);
            //WRITE_TRACE_LOG(_enc_tst, "skip mb count", m_encCtx.SkipMbCount + 1);
            requiredSize += GetUESize(m_encCtx.SkipMbCount + 1);
        }
        //all pervious Mb were skipped
        if ( 0 <= m_encCtx.SkipMbCount)
        {
            //PutUE(&m_encCtx.m_stream, m_encCtx.SkipMbCount + 1);
            //WRITE_TRACE_LOG(_enc_tst, "skip mb count", m_encCtx.SkipMbCount + 1);
            //m_encCtx.SkipMbCount = -1;
            requiredSize += GetUESize(m_encCtx.SkipMbCount + 1);
        }
        //PutUE(&m_encCtx.m_stream, m_pMbInfo->MbType - 2 );
        //WRITE_TRACE_LOG(_enc_tst, "mb type", m_pMbInfo->MbType - 2);
        requiredSize += GetUESize(m_pMbInfo->MbType - 2);
        //Construct Motion Vectors for P Block
        GetRefIndiciesPSlice();
        GetDiffMotionVectorsPSlice();
    }
    else
    {
        //PutUE(&m_encCtx.m_stream, (m_pMbInfo->MbType) - 1 );
        //WRITE_TRACE_LOG(_enc_tst, "mb type", (m_pMbInfo->MbType) - 1);
        requiredSize += GetUESize(m_pMbInfo->MbType - 1);
        //Construct Motion Vectors for P Block
        GetRefIndiciesPSlice();
        GetDiffMotionVectorsPSlice();
    }

    // encode motion vectors
    for (i = 0; i < m_pMbInfo->MvNum; i += 1)
    {
        //PutSE(&m_encCtx.m_stream, mv_diff[i].vector.x);
        //WRITE_TRACE_LOG(_enc_tst, "mv diff x", mv_diff[i].vector.x);
        //PutSE(&m_encCtx.m_stream, mv_diff[i].vector.y);
        //WRITE_TRACE_LOG(_enc_tst, "mv diff y", mv_diff[i].vector.y);
        requiredSize += GetSESize(mv_diff[i].vector.x);
        requiredSize += GetSESize(mv_diff[i].vector.y);
    }
    
    // encode weighting prediction flag
    if (m_encCtx.m_pSlcHeader->mb_weighting_flag)
    {
        //PutBit(&m_encCtx.m_stream, m_pMbInfo->weighting_prediction);
        //WRITE_TRACE_LOG(_enc_tst, "weighting prediction", m_pMbInfo->weighting_prediction);
        requiredSize += 1;
    }
    //else //no to encode
    //{
    //    if mb_weighting flag is zero,
    //    macroblock weighting prediction flag is equal to slice_weighting_flag
    //    m_pMbInfo->weighting_prediction = (Ipp8u) m_decCtx.m_pSlcHeader->slice_weighting_flag;
    //}
    //

    //For all types of pictures
    {
        Ipp32u uTemp;
        Ipp32s mb_qp_delta = 0;

        // encode coded block pattern
        uTemp = CBPOfMacroblock2Code[AVS_INTER][m_pMbInfo->MbCBP  & 0x3f];
        //PutUE(&m_encCtx.m_stream, uTemp & 0x3f );
        //WRITE_TRACE_LOG(_enc_tst, "CBP code", uTemp);
        requiredSize += GetUESize(uTemp & 0x3f);
        
        // save additional chroma bits
        if (AVS_CHROMA_422_FORMAT == m_encCtx.m_pSeqHeader->chroma_format)
        {
            //WRITE_TRACE_LOG(_enc_tst, "CBP code +", uTemp); 
            //PutUE(&m_encCtx.m_stream, ((uTemp >> 6) & 0x3) );
            requiredSize += GetUESize((uTemp >> 6) & 0x3 );
        }

        // encode quantization parameter
        if ((m_pMbInfo->MbCBP) &&
            (0 == m_decCtx.FixedQP))
        {
            //mb_qp_delta = m_pMbInfo->QP - m_encCtx.PreviousQP;
            //PutSE(&m_encCtx.m_stream, mb_qp_delta);
            //WRITE_TRACE_LOG(_enc_tst, "mb qp", m_pMbInfo->QP);
            //WRITE_TRACE_LOG(_enc_tst, "mb qp delta", mb_qp_delta);
            //m_encCtx.PreviousQP = m_pMbInfo->QP;
            requiredSize += GetSESize(mb_qp_delta);
        }
        //    
        {
            Ipp32u i;
            Ipp32u uBlockMask = 1;
            const Ipp16s *pReadCoeffs = m_pReadCoeffs;

            // encode luminance blocks
            for (i = 0; i < 4; i += 1, uBlockMask += uBlockMask)
            {
                if (m_pMbInfo->MbCBP & uBlockMask)
                {
                    requiredSize += avs_GetSizeLumaBlockInter_AVS_1u16s(pReadCoeffs,
                                                                        m_encCtx.ScanType);
                    pReadCoeffs += 64;
                }
            }

            // encode chrominance blocks
            for (; i < m_encCtx.iNumberOfBlocks; i += 1, uBlockMask += uBlockMask)
            {
                if (m_pMbInfo->MbCBP & uBlockMask)
                {
                    requiredSize += avs_GetSizeChromaBlock_AVS_1u16s(pReadCoeffs,
                                                                     m_encCtx.ScanType);
                    pReadCoeffs += 64;
                }
            }
        }

    }
    return requiredSize;
} // Ipp32u AVSCompressor::GetSizePMacroBlock(void)


void AVSCompressor::FillUpMeMbStatPMacroBlock(void)
{
    // fill up MeMbStat structures of MeFrame for feedback mode of AVS_ME
    MeMbStat *curStat = m_encCtx.m_pSlice->m_pPic->m_pMeFrame->stat;
    if (P_Skip == m_pMbInfo->MbType)
    {
        curStat[MbIndex].whole = 0;
        curStat[MbIndex].coeff[0] = 0;
        curStat[MbIndex].MVF[0] = 0;
        curStat[MbIndex].MVB[0] = 0;
        curStat[MbIndex].MbType = 4; //ME_MbFrwSkipped
        curStat[MbIndex].qp = (Ipp16u) m_pMbInfo->QP;
        curStat[MbIndex].dist = 0 ;
    }
    else // (P_Skip != m_pMbInfo)
    {
        Ipp32u i;
        curStat[MbIndex].whole = (Ipp16u) GetSizePMacroBlock();
        curStat[MbIndex].MbType = 1;  // ME_BlockFrw
        curStat[MbIndex].qp = (Ipp16u) m_pMbInfo->QP;
        curStat[MbIndex].MVB[0] = 0;
        curStat[MbIndex].dist = 0 ;
        for (i = 0; i < m_pMbInfo->MvNum; i += 1)
        {
            curStat[MbIndex].MVF[i] = (Ipp16u) (GetSESize(mv_diff[i].vector.x) +
                                                GetSESize(mv_diff[i].vector.y) );
        }
        Ipp32u uBlockMask = 1;
        const Ipp16s *pReadCoeffs = m_pReadCoeffs;

        // encode luminance blocks
        for (i = 0; i < 4; i += 1, uBlockMask += uBlockMask)
        {
            if (m_pMbInfo->MbCBP & uBlockMask)
            {
                //requiredSize += 
                curStat[MbIndex].coeff[i] = (Ipp16u) avs_GetSizeLumaBlockInter_AVS_1u16s(pReadCoeffs,
                                                                                    m_encCtx.ScanType);
                pReadCoeffs += 64;
            }
            else
                curStat[MbIndex].coeff[i] = 0;
        }

        // encode chrominance blocks
        for (; i < m_encCtx.iNumberOfBlocks; i += 1, uBlockMask += uBlockMask)
        {
            if (m_pMbInfo->MbCBP & uBlockMask)
            {
                //requiredSize += 
                curStat[MbIndex].coeff[i] = (Ipp16u)avs_GetSizeChromaBlock_AVS_1u16s(pReadCoeffs,
                                                                                    m_encCtx.ScanType);
                pReadCoeffs += 64;
            }
            else
                curStat[MbIndex].coeff[i] = 0;
        }
        //curStat[MbIndex].coeff[0] = (Ipp16u)requiredSize;
    }
    //currMeFrame->stat[MbIndex].whole = 0;
} // void AVSCompressor::FillUpMeMbStatPMacroBlock(void)


void AVSCompressor::GetRefIndiciesPSlice(void)
{
    // clone reference indecies
    switch (m_pMbInfo->divType)
    {
        // all block have the same reference index
    case Div_16x16:
        m_refIdx[0] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][0];
        break;

        // top blocks have index 0,
        // bottom blocks have index 1
    case Div_16x8:
        m_refIdx[0] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][0];
        m_refIdx[1] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][2];
        break;
        
        // left blocks have index 0,
        // right blocks have index 1
    case Div_8x16:
        m_refIdx[0] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][0];
        m_refIdx[1] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][1];
        break;

        // every block has its own reference index
    default:
        m_refIdx[0] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][0];
        m_refIdx[1] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][1];
        m_refIdx[2] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][2];
        m_refIdx[3] = (Ipp8u) m_pMbInfo->refIdx[AVS_FORWARD][3];
        break;
    }

} //void AVSCompressor::SpecifyRefIndiciesPSlice(void)

void AVSCompressor::GetDiffMotionVectorsPSlice(void)
{
    switch (m_pMbInfo->divType)
    {
    case Div_16x16:
        // get the motion vector prediction & construct motion vector
        GetMotionVectorPredictor16x16(PredForward, 0);
        mv_diff[0] = m_pMbInfo->mv[0][0] - m_mvPred;
        break;

    case Div_16x8:
        // get the motion vector prediction & construct motion vector
        m_neighbours.pNearest = m_pMbInfoTop;
        m_neighbours.pTop = m_pMbInfoTop;
        m_neighbours.pTopRight = m_pMbInfoTopRight;
        m_neighbours.pTopLeft = m_pMbInfoTopLeft;
        GetMotionVectorPredictor16x8(PredForward, 0);
        mv_diff[0] = m_pMbInfo->mv[0][0] - m_mvPred;

        // get the motion vector prediction & construct motion vector
        m_neighbours.pNearest = m_pMbInfoLeft;
        m_neighbours.pTop = m_pMbInfo;
        m_neighbours.pTopRight = NULL;
        m_neighbours.pTopLeft = m_pMbInfoLeft;
        GetMotionVectorPredictor16x8(PredForward, 2);
        mv_diff[1] = m_pMbInfo->mv[0][2] - m_mvPred;
        break;

    case Div_8x16:
        // get the motion vector prediction & construct motion vector
        m_neighbours.pNearest = m_pMbInfoLeft;
        m_neighbours.pLeft = m_pMbInfoLeft;
        m_neighbours.pTopRight = m_pMbInfoTop;
        m_neighbours.pTopLeft = NULL;
        GetMotionVectorPredictor8x16(PredForward, 0);
        mv_diff[0] = m_pMbInfo->mv[0][0] - m_mvPred;

        // get the motion vector prediction & construct motion vector
        m_neighbours.pNearest = (m_pMbInfoTopRight) ? (m_pMbInfoTopRight) : (m_pMbInfoTop);
        m_neighbours.pLeft = m_pMbInfo;
        m_neighbours.pTopRight = m_pMbInfoTopRight;
        m_neighbours.pTopLeft = m_pMbInfoTop;
        GetMotionVectorPredictor8x16(PredForward, 1);
        mv_diff[1] = m_pMbInfo->mv[0][1] - m_mvPred;
        break;

    default:
        // get the motion vector prediction & construct motion vector
        m_neighbours.pLeft = m_pMbInfoLeft;
        m_neighbours.pTop = m_pMbInfoTop;
        m_neighbours.pTopRight = m_pMbInfoTop;
        m_neighbours.pTopLeft = NULL;
        GetMotionVectorPredictor8x8(PredForward, 0);
        mv_diff[0] = m_pMbInfo->mv[0][0] - m_mvPred;

        // get the motion vector prediction & construct motion vector
        m_neighbours.pLeft = m_pMbInfo;
        m_neighbours.pTopRight = m_pMbInfoTopRight;
        m_neighbours.pTopLeft = m_pMbInfoTop;
        GetMotionVectorPredictor8x8(PredForward, 1);
        mv_diff[1] = m_pMbInfo->mv[0][1] - m_mvPred;

        // get the motion vector prediction & construct motion vector
        m_neighbours.pLeft = m_pMbInfoLeft;
        m_neighbours.pTop = m_pMbInfo;
        m_neighbours.pTopRight = m_pMbInfo;
        m_neighbours.pTopLeft = NULL;
        GetMotionVectorPredictor8x8(PredForward, 2);
        mv_diff[2] = m_pMbInfo->mv[0][2] - m_mvPred;

        // get the motion vector prediction & construct motion vector
        m_neighbours.pLeft = m_pMbInfo;
        m_neighbours.pTopRight = NULL;
        m_neighbours.pTopLeft = m_pMbInfo;
        GetMotionVectorPredictor8x8(PredForward, 3);
        mv_diff[3] = m_pMbInfo->mv[0][3] - m_mvPred;

        break;
    }

    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][0].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][0].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][1].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][1].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][2].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][2].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);

} // void AVSDecompressor::ReconstructMotionVectorsPSlice(void)

//static const
//Ipp32u AVSChromaQPTable[64] =
//{
//   0,  1,  2,  3,  4,  5,  6,  7,
//   8,  9, 10, 11, 12, 13, 14, 15,
//  16, 17, 18, 19, 20, 21, 22, 23,
//  24, 25, 26, 27, 28, 29, 30, 31,
//  32, 33, 34, 35, 36, 37, 38, 39,
//  40, 41, 42, 42, 43, 43, 44, 44,
//  45, 45, 46, 46, 47, 47, 48, 48,
//  48, 49, 49, 49, 50, 50, 50, 51
//};

// for debug purpose
//void AVSCompressor::ReconstructPMacroBlock(void)
//{
//    Ipp32u chromaQP;
//
//    WRITE_TRACE_LOG(_rec_tst_enc, "CurrentQP", m_pMbInfo->QP);
//
//    // compensate luminance motion
//    AVSDecompressor::CompensateMotionLumaPMacroBlock();
//
//    // reconstruct luminance blocks
//    if (m_pMbInfo->MbCBP & 0x0f)
//    {
//        ippiReconstructLumaInter_AVS_16s8u_C1R((Ipp16s **) &m_pReadCoeffs,
//                                               m_recCtx.m_pPlanes8u[0],
//                                               m_recCtx.m_iPitch,
//                                               m_pMbInfo->NumCoeffs,
//                                               m_pMbInfo->MbCBP,
//                                               m_pMbInfo->QP);
//    }
//
//    WRITE_TRACE_LOG_BYTE_BLOCK(_rec_tst_enc, "Y block", m_recCtx.m_pPlanes8u[0], m_recCtx.m_iPitch, 16, 16);
//
//    chromaQP = AVSChromaQPTable[m_pMbInfo->QP];
//    WRITE_TRACE_LOG(_rec_tst_enc, "chromaQP", chromaQP);
//
//    // compensate chrominance motion
//    AVSDecompressor::CompensateMotionChromaPMacroBlock();
//
//    // reconstruct chrominance blocks
//    if (m_pMbInfo->MbCBP & 0x0f0)
//    {
//        ippiReconstructChromaInter_AVS_16s8u_C1R((Ipp16s **) &m_pReadCoeffs,
//                                                 m_recCtx.m_pPlanes8u[1],
//                                                 m_recCtx.m_pPlanes8u[2],
//                                                 m_recCtx.m_iPitch,
//                                                 m_pMbInfo->NumCoeffs + 4,
//                                                 m_pMbInfo->MbCBP >> 4,
//                                                 chromaQP);
//    }
//
//    WRITE_TRACE_LOG_BYTE_BLOCK(_rec_tst_enc, "U block", m_recCtx.m_pPlanes8u[1], m_recCtx.m_iPitch, 8, 8);
//    WRITE_TRACE_LOG_BYTE_BLOCK(_rec_tst_enc, "V block", m_recCtx.m_pPlanes8u[2], m_recCtx.m_iPitch, 8, 8);
//
//} // void AVSCompressor::ReconstructPMacroBlock(void)



} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_ENCODER)
